﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once
#include <vector>
#include "OwnerPtr.h"
#include "MeshOperateErrorCode.h"
#include "MeshMeshIntersectData.h"
#include "DiscreteEpsilonType.h"

namespace gcmp
{
    class IMesh;
    class IPlane;
    class Vector3d;
    class Vector2d;
    class IPolyCurve3d;
    struct MeshSimplifyOptions;
    class IBody;

    class IMeshOperate
    {
    public:
        virtual ~IMeshOperate() {};

        /// \brief    平面切割网格
        ///
        /// \param  pMesh        网格
        /// \param  pPlane       平面
        /// \param positiveMeshParts     平面法向的分割网格
        /// \param negativeMeshParts     平面负法向的分割网格
        /// \param pErrorCode     错误码
        /// \return    true,成功； false,失败
        virtual bool Split(const IMesh* pMesh, const IPlane* pPlane, std::vector<OwnerPtr<IMesh>>& positiveMeshParts,
            std::vector<OwnerPtr<IMesh>>& negativeMeshParts, MeshOperateErrorCode* pErrorCode) const = 0;

        /// \brief    生成Delaunay三角网格
        /// \param std::vector<Vector3d>& points    输入的点云
        /// \param constraintPoints   如果用户限制了边缘边，应将所有边缘点在points中的索引序号在此输入，输入规则为逆时针依次输入
        /// \return   三角网格
        virtual OwnerPtr<IMesh> CreateDelaunayMeshFromPoints(const std::vector<Vector3d>& points, const std::vector<unsigned int> &constraintPoints)const = 0;

        /// \brief     体和体mesh求交;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        virtual MeshBoolErrorCode MeshBoolIntersect(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh) const = 0;

        /// \brief     体和体mesh求差;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        virtual MeshBoolErrorCode MeshBoolSubtract(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh) const = 0;

        /// \brief     体和体mesh求并;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        virtual MeshBoolErrorCode MeshBoolUnite(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh) const = 0;
        
        /// \brief 使用多边形按照给定方向对三角网进行切割
        /// \param[in]  pMesh  输入的三角网数据
        /// \param[in]  polygon  输入的多边形中的顶点数据，多边形默认是闭合的
        /// \param[in]  direction  给定的切割方向
        /// \param[out]  resultInnerMesh  输出三角网在多边形中的部分
        /// \param[out]  resultOuterMesh  输出三角网在多边形外的部分
        /// \return 开洞错误码
        virtual MeshOpenHoleErrorCode OpenHoleBaseDirection(const IMesh* pMesh, const std::vector<Vector3d>& polygon, const Vector3d& direction, OwnerPtr<IMesh>& resultInnerMesh, OwnerPtr<IMesh>& resultOuterMesh) const = 0;

        /// \brief     mesh和mesh求交线;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  intersectLines      交线数据;
        virtual bool GetMeshMeshIntersectLines(const IMesh* pMesh1, const IMesh* pMesh2, std::vector<OwnerPtr<IPolyCurve3d>>& intersectLines) = 0;

        /*!
        * @brief    简化三角网
        * @param[in] pMesh             传入三角网数据
        * @param[in] options               简化过程中的参数设置: CompressionRatio范围为(0.0,1.0)
        * @param[out] outMesh             输出简化后的三角网数据
        * @return    简化错误码
        */
        virtual MeshSimplifyErrorCode Simplify(const IMesh* pMesh, const MeshSimplifyOptions& options, OwnerPtr<IMesh>& outMesh) const = 0;

        /*!
        * @brief      离散点集约束Delaunary三角化(不包含内边界约束)
        * @param[in] pts    输入的点云
        * @param[in] constraintPts   如果用户限制了边缘边，应将所有边缘点在pts中的索引序号在此输入，输入规则为逆时针依次输入
        * @param[in] direction  投影方向
        * @return    由点云三角化生成的三角网, 失败时返回空
        */
        virtual OwnerPtr<IMesh> CreateXYTriangulation(const std::vector<Vector3d>& pts, const std::vector<unsigned int>& constraintPts, const Vector3d& direction)const = 0;

        /*!
        * @brief      离散点集约束Delaunary三角化(包含内边界约束)
        * @param[in] constraintPts    输入的约束边上的点云,嵌套vector的第一个元素为外环,后面的为内环，外环点集要按逆时针依次输入，内环要按顺时针依次输入
        * @param[in] pts  内部点,可以超过边界，会被自动过滤掉
        * @param[in] direction  投影方向，默认为往XY平面上投影
        * @return    由点云三角化生成的三角网, 失败时返回空
        */
        virtual OwnerPtr<IMesh> CreateXYTriangulation(const std::vector<std::vector<Vector3d>>& constraintPts, const std::vector<Vector3d>& pts, const Vector3d& direction)const = 0;

        /*!
        * @brief  由Brepbody创建水密的Mesh
        * @param[in] pBody  输入的Brepbody
        * @param[in] dDistanceEpsilon  距离精度，弓高大于此值将继续细分，需大于0
        * @param[in] dAngleEpsilon  角度精度（弧度），法向锥半角大于此值将继续细分，需大于0
        * @param[in] dEdgeLengthRatio  最大离散边长与体对角线的比例，需大于等于0，0表示无效
        * @param[in] deType  几何离散的容差给定方式
        * @param[in] outMesh  创建的水密Mesh
        * @return  Brepbody转水密Mesh的错误码
        */
        virtual MeshFromBrepBodyErrorCode CreateMeshFromBrepBody(const IBody* pBody, double dDistanceEpsilon, double dAngleEpsilon, double dEdgeLengthRatio, DiscreteEpsilonType deType, OwnerPtr<IMesh>& outMesh) const = 0;

        /*!
        * @brief      网格网格求交线段
        * @param[in]     pMesh1           第一个网格
        * @param[in]     pMesh2           第二个网格
        * @param[in]     rType           是否重构求交网格选项
        * @param[out] intersectSegments 两个网格求交得到的交线边 pair（有序的交线边，是否成环）
        * @return     网格求交错误码
        * @attention  Mesh体系设置统一容差，系统默认距离容差为1e-4,用户可以通过容差类MeshTolerance的SetDistTol函数来设置距离容差
        *             设置方式为MeshTolerance::SetDistTol(double distTol)
        */
        virtual MeshMeshIntErrorCode MeshMeshIntersect(IMesh* pMesh1, IMesh* pMesh2, ReConstructMeshType rType, std::vector<std::pair<std::vector<MeshMeshIntSegment>, bool>>& intersectSegments)const = 0;

        /*!
        * @brief 修复mesh的法向
        * @param[in] pMesh  输入mesh
        * @return   输出的mesh,修复失败返回空
        */
        virtual OwnerPtr<IMesh> FixMeshNormals(const IMesh* pMesh)const = 0;

        /*!
        * @brief 壳网格裁剪壳网格
        * @param[in] pMesh1 第一个三角网格
        * @param[in] pMesh2 第二个三角网格
        * @param[in, out] outUpMeshes    pMesh1裁剪pMesh2,pMesh2位于pMesh1法向正向的部分，并且按连通性拆分成若干单连通的网格
        * @param[in, out] outDownMeshes  pMesh1裁剪pMesh2,pMesh2位于pMesh1法向负向的部分，并且按连通性拆分成若干单联通的网格
        * @return 布尔运算错误码  @ref MeshBoolErrorCode
        * @attention  1、pMesh1和pMesh2都要求是非封闭网格
        *             2、pMesh1必须要能够完全切开pMesh2
        *             3、Mesh体系设置统一容差，系统默认距离容差为1e-4,用户可以通过容差类MeshTolerance的SetDistTol函数来设置距离容差
        *             设置方式为MeshTolerance::SetDistTol(double distTol)
        */
        virtual MeshBoolErrorCode ShellMeshSplitShellMesh(const IMesh* pMesh1, const IMesh* pMesh2, std::vector<OwnerPtr<IMesh>>& outUpMeshes, std::vector<OwnerPtr<IMesh>>& outDownMeshes)const = 0;

        /*!
        * @brief 壳网格裁剪体网格
        * @param[in] pMesh1 第一个三角网格
        * @param[in] pMesh2 第二个三角网格
        * @param[in, out] outUpMeshs    pMesh1裁剪pMesh2,pMesh2位于pMesh1法向正向的部分，并且按连通性拆分成若干单连通的网格
        * @param[in, out] outDownMeshs  pMesh1裁剪pMesh2,pMesh2位于pMesh1法向负向的部分，并且按连通性拆分成若干单联通的网格
        * @return 布尔运算错误码  @ref EnMeshBoolErrorCode
        * @attention  1、pMesh1要求是非封闭网格，pMesh2要求是封闭网格
        *             2、pMesh1必须要能够完全切开pMesh2
        *             3、Mesh体系设置统一容差，系统默认距离容差为1e-4,用户可以通过容差类CMeshTolerance的SetDistTol函数来设置距离容差
        *             设置方式为CMeshTolerance::GetInstance().SetDistTol(double distTol)
        */
        virtual MeshBoolErrorCode ShellMeshSplitBodyMesh(const IMesh* pMesh1, const IMesh* pMesh2, std::vector<OwnerPtr<IMesh>>& outUpMeshes, std::vector<OwnerPtr<IMesh>>& outDownMeshes)const = 0;
        
        /*!
        * @brief      Mesh拉伸成体
        * @param[in]      pShellMesh  壳网格
        * @param[in]      dir        拉伸方向
        * @param[in]      length     拉伸长度
        * @return   返回体网格，失败则返回空
        */
        virtual OwnerPtr<IMesh> ExtrudeFromShellMesh(const IMesh* pShellMesh, const gcmp::Vector3d& dir, double length)const = 0;

        /*!
        * @brief          Mesh围合成体
        * @param[in]      pTopMesh       上方网格
        * @param[in]      pBottomMesh    下方网格
        * @param[in]      isOnlyUpBody   是否只需要计算上方网格以下，下方网格以上围合成的体
        * @param[in, out] outUpMeshs     上方网格以下，下方网格以上围合成的体，并按连通性拆分
        * @param[in, out] outDownMeshes  上方网格以上，下方网格以下围合成的体，按按连通性拆分
        * @param[in]      direct         投影方向
        * @param[in]      dDistEps       距离容差
        * @return 网格围合错误码  @ref MeshShellSurroundBodyErrorCode
        * @attention  1、pTopMesh和pBottomMesh都要求是非封闭网格
        *             2、壳网格指——非封闭网格,体网格指——封闭网格
        */
        virtual MeshShellSurroundBodyErrorCode EncloseShellMeshes(const IMesh* pTopMesh, const IMesh* pBottomMesh, bool isOnlyUpBody, std::vector<OwnerPtr<IMesh>>& outUpMeshs, std::vector<OwnerPtr<IMesh>>& outDownMeshes, const Vector3d& direct,double dDistEps)const = 0;

        /*!
        * @brief          沿指定方向获取两个网格的可见部分。
        * @param[in]      pSheelMesh1       第一个单联通的壳网格
        * @param[in]      pSheelMesh2       第二个单联通的壳网格
        * @param[in]      direction   方向
        * @param[in, out] outMesh     可见部分组成的网格 
        * @return true：成功，false：失败
        */
        virtual bool GetVisibleParts(const IMesh* pSheelMesh1, const IMesh* pSheelMesh2, const Vector3d& direction, OwnerPtr<IMesh>& outMesh)const = 0;

        /// \brief     体和体mesh求交;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        /// \param  pMapSourceMeshIndex        结果网格和源网格的映射关系;
        /// \param  dDistEps            容差;
        /// \param  isBodyBool          是否体和体运算,目前体和壳体运算有问题;
        GCMP_OBSOLETE_API(2023/11/01, IMeshOperate::MeshBoolIntersect(const IMesh*, const IMesh*, OwnerPtr<IMesh>&)) 
            virtual MeshBoolErrorCode Intersect(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh, std::vector<Vector2d>* pMapSourceMeshIndex, double dDistEps, bool isBodyBool) const = 0;

        /// \brief     体和体mesh求差;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        /// \param  pMapSourceMeshIndex        结果网格和源网格的映射关系;
        /// \param  dDistEps            容差
        /// \param  isBodyBool          是否体和体运算,目前体和壳体运算有问题;
        GCMP_OBSOLETE_API(2023/11/01, IMeshOperate::MeshBoolSubtract(const IMesh*, const IMesh*, OwnerPtr<IMesh>&))
            virtual MeshBoolErrorCode Subtract(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh, std::vector<Vector2d>* pMapSourceMeshIndex, double dDistEps, bool isBodyBool) const = 0;

        /// \brief     体和体mesh求并;
        /// \param  pMesh1              网格1
        /// \param  pMesh2              网格2
        /// \param  resultMesh          结果网格;
        /// \param  pMapSourceMeshIndex        结果网格和源网格的映射关系;
        /// \param  dDistEps            容差;
        /// \param  isBodyBool          是否体和体运算,目前体和壳体运算有问题;
        GCMP_OBSOLETE_API(2023/11/01, IMeshOperate::MeshBoolUnite(const IMesh*, const IMesh*, OwnerPtr<IMesh>&)) 
            virtual MeshBoolErrorCode Unite(const IMesh* pMesh1, const IMesh* pMesh2, OwnerPtr<IMesh>& resultMesh, std::vector<Vector2d>* pMapSourceMeshIndex, double dDistEps, bool isBodyBool) const = 0;
    };
}
